//-----------------------------------------------------------------------
//
//  Written Dec-2007 by Trevor Taylor, Software Technology, Australia
//
//  $File: StingerDriveByWireTypes.cs $ $Revision: 1 $
//-----------------------------------------------------------------------
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;

using System;
using System.Collections.Generic;
using W3C.Soap;
using Microsoft.Dss.Core.DsspHttp;
using System.ComponentModel;

using stinger = ProMRDS.Robotics.StingerDriveByWire;

namespace ProMRDS.Robotics.StingerDriveByWire
{
    
    public static class Contract
    {
        public const string Identifier = "http://www.promrds.com/contracts/2007/11/stingerdrivebywire.html";
    }

    [DataContract]
    public class StingerDriveByWireState
    {
        // The Headless field indicates if we should run without a GUI
        private bool _headless;

        [DataMember]
        public bool Headless
        {
            get { return _headless; }
            set { _headless = value; }
        }

        // Can run with the Motor disabled for testing
        private bool _motorEnabled;

        [DataMember]
        public bool MotorEnabled
        {
            get { return _motorEnabled; }
            set { _motorEnabled = value; }
        }

        private bool _wanderEnabled;

        [DataMember]
        public bool WanderEnabled
        {
            get { return _wanderEnabled; }
            set { _wanderEnabled = value; }
        }

        private WanderModes _wanderMode;

        [DataMember]
        public WanderModes WanderMode
        {
            get { return _wanderMode; }
            set { _wanderMode = value; }
        }

        private int _wanderCounter;

        [DataMember]
        public int WanderCounter
        {
            get { return _wanderCounter; }
            set { _wanderCounter = value; }
        }

        private double _irLeft;

        [DataMember]
        public double IRLeft
        {
            get { return _irLeft; }
            set { _irLeft = value; }
        }

        private double _irFront;

        [DataMember]
        public double IRFront
        {
            get { return _irFront; }
            set { _irFront = value; }
        }
        private double _irRight;

        [DataMember]
        public double IRRight
        {
            get { return _irRight; }
            set { _irRight = value; }
        }
    }

    // Modes that the robot can be in while wandering
    [DataContract]
    public enum WanderModes
    {
        None,
        DriveStraight,
        VeerLeft,
        VeerRight,
        TurnLeft,
        TurnRight,
        BackUp
    }

    [ServicePort]
    public class StingerDriveByWireOperations : PortSet
    {
        // These changes from the previous way of declaring a PortSet
        // are necessary to work with CF when you have more than 8
        // ports in the set
        public StingerDriveByWireOperations()
            : base(
        typeof(DsspDefaultLookup),
        typeof(DsspDefaultDrop),
        typeof(Get),
        typeof(Replace),
        typeof(Load),
        typeof(MotionCommand),
        typeof(Wander),
        typeof(Quit)
            )
        {}

        public virtual PortSet<Microsoft.Dss.ServiceModel.Dssp.DefaultUpdateResponseType,Fault> MotionCommand(int leftPower, int rightPower)
        {
            MotionRequest body = new MotionRequest(leftPower, rightPower);
            MotionCommand op = new MotionCommand(body);
            this.Post(op);
            return op.ResponsePort;

        }

        // Implicit Conversions
        public static implicit operator Port<MotionCommand>(StingerDriveByWireOperations portSet)
        {
            if (portSet == null) return null;
            return (Port<MotionCommand>)portSet[typeof(MotionCommand)];
        }

        public void Post(MotionCommand m)
        {
            PostUnknownType(m);
        }

        public void Post(Wander w)
        {
            PostUnknownType(w);
        }

        public void Post(Quit q)
        {
            PostUnknownType(q);
        }

    }

    public class Get : Get<GetRequestType, PortSet<StingerDriveByWireState, Fault>>
    {
    }

    public class Replace : Replace<StingerDriveByWireState, PortSet<DefaultReplaceResponseType, Fault>>
    {
        public Replace()
        {
        }

        public Replace(StingerDriveByWireState body)
            : base(body)
        {
        }
    }


    public class Load : Submit<LoadRequest, PortSet<DefaultSubmitResponseType, Fault>>
    {
        public Load()
            : base(new LoadRequest())
        {
        }
    }

    [DataContract]
    public class LoadRequest { }


    public class Wander : Update<WanderRequest, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public Wander()
        {
        }

        public Wander(bool state)
            : base(new WanderRequest(state))
        {
        }
    }

    [DataContract]
    [DataMemberConstructor]
    public class WanderRequest
    {
        private bool _status;

        [DataMember, DataMemberConstructor]
        [Description("To wander or not ...")]
        public bool Status
        {
            get { return this._status; }
            set { this._status = value; }
        }

        public WanderRequest()
        {
        }
        public WanderRequest(bool state)
        {
            Status = state;
        }
    }


    public class MotionCommand : Update<MotionRequest, PortSet<DefaultUpdateResponseType, Fault>>
    {
        public MotionCommand()
            : base(new MotionRequest())
        {
        }
        public MotionCommand(MotionRequest body)
            : base()
        {
            this.Body = body;
        }
        public MotionCommand(int left, int right)
            : base()
        {
            this.Body.LeftPower = left;
            this.Body.RightPower = right;
        }
    }

    [DataContract]
    [DataMemberConstructor]
    public class MotionRequest
    {
        private int _leftPower;
        private int _rightPower;

        [DataMember, DataMemberConstructor(Order=1)]
        [Description("Left Motor Power")]
        public int LeftPower
        {
            get { return this._leftPower; }
            set { this._leftPower = value; }
        }

        [DataMember, DataMemberConstructor(Order=2)]
        [Description("Right Motor Power")]
        public int RightPower
        {
            get { return this._rightPower; }
            set { this._rightPower = value; }
        }

        public MotionRequest()
        {
        }
        public MotionRequest(int left, int right)
        {
            this._leftPower = left;
            this._rightPower = right;
        }
    }


    public class Quit : Submit<QuitRequest, PortSet<DefaultSubmitResponseType, Fault>>
    {
        public Quit()
            : base(new QuitRequest())
        {
        }
    }

    [DataContract]
    public class QuitRequest { }

}
